//===============================================================================
// Microsoft Architecture Strategy Team
// LitwareHR - SaaS Sample Application
//===============================================================================
// Copyright  Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================

using System;
using System.Collections.Generic;
using System.Text;
using System.Workflow.Runtime;
using System.Workflow.Runtime.Hosting;
using System.Workflow.Runtime.Tracking;
using System.Workflow.Activities;
using System.Configuration;
using System.Data.Common;
using System.Data;
using System.Globalization;

using Shp.Runtime.Contract;

using LitwareHR.Recruiting.Contract;
using LitwareHR.Recruiting.Workflows;
using LitwareHR.Recruiting.Workflows.Activities;

using Microsoft.Practices.EnterpriseLibrary.Data;

namespace LitwareHR.Recruiting.Services
{
    static public class ProcessLogic
    {
        static private WorkflowRuntime _runtime;

        static public WorkflowRuntime Runtime
        {
            get
            {
                if (_runtime == null)
                {
                    _runtime = new WorkflowRuntime("WorkflowRuntime");
                    if (_runtime.GetService<ExternalDataExchangeService>() != null)
                    {
                        _runtime.GetService<ExternalDataExchangeService>().AddService(new RecruitingMoniker());
                        _runtime.GetService<ExternalDataExchangeService>().AddService(new EvaluationMoniker());
                    }
                    _runtime.AddService(new WorkflowFactoryRuntimeService());
                    _runtime.StartRuntime();
                }
                return _runtime;
            }
        }

        static public Guid OpenRecruitingProcess(Position position)
        {
            Dictionary<string, object> parameters = new Dictionary<string, object>();
            parameters.Add("TenantId", position.TenantId);
            parameters.Add("PositionId", position.Id);
            parameters.Add("Position", position);
            WorkflowInstance workflowInstance = Runtime.CreateWorkflow(typeof(RecruitingProcess), parameters);
            workflowInstance.Start();
            RunWorkflowInScheduler(workflowInstance.InstanceId);

            return workflowInstance.InstanceId;
        }

        static public List<Guid> GetOpenPositionList(Guid tenantId)
        {
            SqlTrackingQuery sqlTrackingQuery = new SqlTrackingQuery(ConfigurationManager.ConnectionStrings["TrackingStore"].ConnectionString);
            SqlTrackingQueryOptions options = new SqlTrackingQueryOptions();
            options.WorkflowType = typeof(RecruitingProcess);
            options.WorkflowStatus = WorkflowStatus.Running;
            options.TrackingDataItems.Add(new TrackingDataItemValue("RecruitingProcess", "TenantId", tenantId.ToString()));

            IList<SqlTrackingWorkflowInstance> workflows = sqlTrackingQuery.GetWorkflows(options);
            List<Guid> list = new List<Guid>();
            foreach (SqlTrackingWorkflowInstance workflow in workflows)
            {
                Guid positionId = Guid.Empty;
                int activityEventsCount = workflow.ActivityEvents.Count;
                if (activityEventsCount > 0)
                {
                    ActivityTrackingRecord record = (ActivityTrackingRecord)workflow.ActivityEvents[activityEventsCount - 1];
                    foreach (TrackingDataItem dataItem in record.Body)
                    {
                        switch (dataItem.FieldName)
                        {
                            case "PositionId":
                                positionId = (Guid)dataItem.Data;
                                list.Add(positionId);
                                break;
                        }
                    }
                }
                
            }
            return list;
        }

        static private void RunWorkflowInScheduler(Guid instanceId)
        {
            ManualWorkflowSchedulerService scheduler = Runtime.GetService<ManualWorkflowSchedulerService>();
            scheduler.RunWorkflow(instanceId);
        }

        static public StringPair[][] GetRecruitingWorkflowListByApplicant(Guid tenantId, Upn upn, bool isOpen)
        {
            List<StringPair[]> recruitingWorkflows = new List<StringPair[]>();

            Database db = DatabaseFactory.CreateDatabase(Constants.DB.TrackingStore);
            Dictionary<Guid, string> list = new Dictionary<Guid, string>();
            string sql = string.Format(CultureInfo.CurrentCulture, Constants.DB.SqlForSelectRecruitingWorkflowIdsByApplicant, tenantId, upn.ToString());
            using (DbCommand command = db.GetSqlStringCommand(sql))
            {
                DataSet ds = db.ExecuteDataSet(command);
                long eventId = 0;
                Guid workflowInstanceId = Guid.Empty;
                foreach (DataRow row in ds.Tables[0].Rows)
                {
                    eventId = (long)row["EventId"];
                    workflowInstanceId = (Guid)row["WorkflowInstanceId"];

                    string rpSql = string.Format(CultureInfo.CurrentCulture, Constants.DB.SqlForSelectRecruitingWorkflowListByWorkflowIdAndEventId, workflowInstanceId, eventId);
                    using (DbCommand commandWorkflow = db.GetSqlStringCommand(rpSql))
                    {
                        DataSet workflowDataSet = db.ExecuteDataSet(commandWorkflow);
                        string applicantUsername = "";
                        string waitingFor = "";
                        string nextStep = "";
                        foreach (DataRow workflowDataRow in workflowDataSet.Tables[0].Rows)
                        {
                            switch (workflowDataRow["FieldName"].ToString())
                            {
                                case "ApplicantUsername":
                                    applicantUsername = (string)workflowDataRow["Data_Str"].ToString();
                                    break;
                                case "WaitingFor":
                                    waitingFor = (string)workflowDataRow["Data_Str"];
                                    break;
                                case "NextStep":
                                    nextStep = (string)workflowDataRow["Data_Str"];
                                    break;
                            }
                        }
                        List<StringPair> submission = new List<StringPair>();
                        submission.Add(new StringPair("WorkflowId", workflowInstanceId.ToString()));
                        submission.Add(new StringPair("Applicant", applicantUsername));
                        submission.Add(new StringPair("Waiting For", waitingFor));
                        submission.Add(new StringPair("NextStep", nextStep));
                        recruitingWorkflows.Add(submission.ToArray());
                    }
                }
            }
            return recruitingWorkflows.ToArray();
        }

        static public StringPair[][] GetRecruitingWorkflowList(Guid tenantId, bool isOpen)
        {
            List<StringPair[]> recruitingWorkflows = new List<StringPair[]>();

            Database db = DatabaseFactory.CreateDatabase(Constants.DB.TrackingStore);
            Dictionary<Guid, string> list = new Dictionary<Guid, string>();
            string sql = string.Format(CultureInfo.CurrentCulture, Constants.DB.SqlForSelectRecruitingWorkflowIds, tenantId);
            using (DbCommand command = db.GetSqlStringCommand(sql))
            {
                DataSet ds = db.ExecuteDataSet(command);
                long eventId = 0;
                Guid workflowInstanceId = Guid.Empty;
                foreach (DataRow row in ds.Tables[0].Rows)
                {
                    eventId = (long)row["EventId"];
                    workflowInstanceId = (Guid)row["WorkflowInstanceId"];

                    string rpSql = string.Format(CultureInfo.CurrentCulture, Constants.DB.SqlForSelectRecruitingWorkflowListByWorkflowIdAndEventId, workflowInstanceId, eventId);
                    using (DbCommand commandWorkflow = db.GetSqlStringCommand(rpSql))
                    {
                        DataSet workflowDataSet = db.ExecuteDataSet(commandWorkflow);
                        string applicantUsername = "";
                        string waitingFor = "";
                        string nextStep = "";
                        foreach (DataRow workflowDataRow in workflowDataSet.Tables[0].Rows)
                        {
                            switch (workflowDataRow["FieldName"].ToString())
                            {
                                case "ApplicantUsername":
                                    applicantUsername = (string)workflowDataRow["Data_Str"].ToString();
                                    break;
                                case "WaitingFor":
                                    waitingFor = (string)workflowDataRow["Data_Str"];
                                    break;
                                case "NextStep":
                                    nextStep = (string)workflowDataRow["Data_Str"];
                                    break;
                            }
                        }
                        List<StringPair> submission = new List<StringPair>();
                        submission.Add(new StringPair("WorkflowId", workflowInstanceId.ToString()));
                        submission.Add(new StringPair("Applicant", applicantUsername));
                        submission.Add(new StringPair("Waiting For", waitingFor));
                        submission.Add(new StringPair("NextStep", nextStep));
                        recruitingWorkflows.Add(submission.ToArray());
                    }
                }
            }
            return recruitingWorkflows.ToArray();         
        }

        static public void SubmitResume(Resume resume, Upn upn)
        {
            RecruitingMoniker service = Runtime.GetService<RecruitingMoniker>();
            Guid recruitingProcessId = GetRecruitingProcessByPositionId(resume.PositionId);
            service.SubmitResume(recruitingProcessId, resume, upn);
            RunWorkflowInScheduler(recruitingProcessId);
        }

        static private Guid GetRecruitingProcessByPositionId(Guid positionId)
        {
            SqlTrackingQuery sqlTrackingQuery = new SqlTrackingQuery(ConfigurationManager.ConnectionStrings["TrackingStore"].ConnectionString);
            SqlTrackingQueryOptions options = new SqlTrackingQueryOptions();
            options.WorkflowStatus = WorkflowStatus.Running;
            options.WorkflowType = typeof(RecruitingProcess);
            options.TrackingDataItems.Add(new TrackingDataItemValue("RecruitingProcess", "PositionId", positionId.ToString()));

            IList<SqlTrackingWorkflowInstance> workflows = sqlTrackingQuery.GetWorkflows(options);

            if (workflows.Count > 0)
                return workflows[workflows.Count - 1].WorkflowInstanceId;

            else
                return Guid.Empty;
        }

        static public void SubmitInterview(Interview interview, Upn upn)
        {
            EvaluationMoniker service = Runtime.GetService<EvaluationMoniker>();
            Guid evaluationProcessWorkflowId = interview.WorkflowId;
            service.SubmitInterview(evaluationProcessWorkflowId, interview, upn);
            RunWorkflowInScheduler(evaluationProcessWorkflowId);
        }

        static public void SubmitNegotiation(Negotiation negotiation, Upn upn)
        {
            EvaluationMoniker service = Runtime.GetService<EvaluationMoniker>();
            Guid evaluationProcessWorkflowId = negotiation.WorkflowId;
            service.SubmitNegotiation(evaluationProcessWorkflowId, negotiation, upn);
            RunWorkflowInScheduler(evaluationProcessWorkflowId);
        }

        static public void SubmitAcceptance(Acceptance acceptance, Upn upn)
        {
            EvaluationMoniker service = Runtime.GetService<EvaluationMoniker>();
            Guid evaluationProcessWorkflowId = acceptance.WorkflowId;
            service.SubmitAcceptance(evaluationProcessWorkflowId, acceptance, upn);
            RunWorkflowInScheduler(evaluationProcessWorkflowId);
        }

        static public void SubmitRejection(Rejection rejection, Upn upn)
        {
            EvaluationMoniker service = Runtime.GetService<EvaluationMoniker>();
            Guid evaluationProcessWorkflowId = rejection.WorkflowId;
            service.SubmitRejection(evaluationProcessWorkflowId, rejection, upn);
            RunWorkflowInScheduler(evaluationProcessWorkflowId);
        }
    }
}
